/*
**    Copyright (C) 2003-2011 Institute for Systems Biology
**                            Seattle, Washington, USA.
**
**    This library is free software; you can redistribute it and/or
**    modify it under the terms of the GNU Lesser General Public
**    License as published by the Free Software Foundation; either
**    version 3 of the License, or (at your option) any later version.
**
**    This library is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
**    Lesser General Public License for more details.
**
**    You should have received a copy of the GNU Lesser General Public
**    License along with this library; if not, write to the Free Software
**    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*/

package org.systemsbiology.iteration;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.systemsbiology.util.Filter;

/**
 * An iterator that skips certain elements, as deemed by a filter. To provide
 * an accurate hasNext(), this iterator engages in one-step lookahead behavior.
 * @author anorberg
 *
 * @param <E> Yield type of both this iterator and the underlying iterator.
 */
public class FilteredIterator<E> implements Iterator<E> {

	private Iterator<? extends E> backingIterator;
	private E next = null;
	private boolean hasMoreValues = true;
	private Filter<? super E> acceptor;
	
	public FilteredIterator(Iterator<? extends E> iterator, Filter<? super E> filter){
		if(iterator == null){
			throw new NullPointerException("Iterator null in FilteredIterator constructor");		
		}
		if(filter == null){
			throw new NullPointerException("Filter null in FilteredIterator constructor");
		}
		this.acceptor = filter;
		this.backingIterator = iterator;
		lookahead();
	}
	
	private void lookahead(){
		while(backingIterator.hasNext()){
			E value = backingIterator.next();
			if(acceptor.accept(value)){
				next = value;
				return;
			}
		}
		//fall out: no more values
		hasMoreValues = false;
	}
	
	@Override
	public boolean hasNext() {
		return hasMoreValues;
	}

	@Override
	public E next() {
		if(!hasMoreValues){
			throw new NoSuchElementException("FilteredIterator ran out of values");
		}
		E value = next;
		lookahead();
		return value;
	}

	@Override
	public void remove() {
		throw new UnsupportedOperationException("FilteredIterator can't pass remove() calls through");
	}

}
